import pandas as pd
import re
import ast
import numpy as np
from multiprocessing import Pool
import time


# Load the lexicons

lex = pd.read_csv('Final Datasets/DLUT_reshaped_final_Synonym_Expanded.csv', low_memory=False)
lex = lex.drop('wClass', axis=1)

antiLex = pd.read_csv('Final Datasets/Anti-DLUT_reshaped_final_Synonym_Expanded.csv', low_memory=False)
antiLex = antiLex.drop('wClass', axis=1)

antiAntiLex = pd.read_csv('Final Datasets/Anti-Anti-DLUT_reshaped_final_Synonym_Expanded.csv', low_memory=False)
antiAntiLex = antiAntiLex.drop('wClass', axis=1)

emoWordList = lex['word'].values
emoWordList = emoWordList.tolist()

negateWords = pd.read_csv('Final Datasets/negation words.csv', low_memory=False)
negateWords = negateWords['negateWord'].values
negateWords = negateWords.tolist()

degreeWords = pd.read_csv('Final Datasets/degree words.csv', low_memory=False)
degreeWords_dict = dict(zip(degreeWords['degreeWord'], degreeWords['degree']))

column_names = list(lex.columns)
column_names.remove('word')

# Define functions

def isOdd(number):
    return number % 2 != 0

def getWordEmos(word, negate = 0, negateFirst = False, negDegNeg = False, degreeYes = False, degrees = 1):

    if negate == 0:
        if not degreeYes:
            wEmos = lex[lex['word'] == word]
            wEmos_dict = wEmos.to_dict(orient='records')[0]
            wEmos_dict.pop('word')
            # print(wEmos_dict)
            return wEmos_dict
        else:
            wEmos = lex[lex['word'] == word]
            wEmos_dict = wEmos.to_dict(orient='records')[0]
            wEmos_dict.pop('word')
            wEmos_dict = {key: (value * degrees if 'Intensity' in key or 'With' in key else value)
                for key, value in wEmos_dict.items()}
            # print(wEmos_dict)
            return wEmos_dict
    elif negate == 1:
        if not degreeYes:
            wEmos = antiLex[antiLex['word'] == word]
            wEmos_dict = wEmos.to_dict(orient='records')[0]
            wEmos_dict.pop('word')
            # print(wEmos_dict)
            return wEmos_dict
        else:
            if not negateFirst:
                wEmos = antiLex[antiLex['word'] == word]
                wEmos_dict = wEmos.to_dict(orient='records')[0]
                wEmos_dict.pop('word')
                wEmos_dict = {key: (value * degrees if 'Intensity' in key or 'With' in key else value)
                    for key, value in wEmos_dict.items()}
                # print(wEmos_dict)
                return wEmos_dict
            else: 
                if lex[lex['word'] == word]['IntensityWithSign'].item() < 0:
                    wEmos = antiAntiLex[antiAntiLex['word'] == word]
                    wEmos_dict = wEmos.to_dict(orient='records')[0]
                    wEmos_dict.pop('word')
                    # print(wEmos_dict)
                    return wEmos_dict 
                else:
                    wEmos = antiLex[antiLex['word'] == word]
                    wEmos_dict = wEmos.to_dict(orient='records')[0]
                    wEmos_dict.pop('word')
                    # print(wEmos_dict)
                    return wEmos_dict
    else:
        if isOdd(negate):
            wEmos = antiLex[antiLex['word'] == word]
            wEmos_dict = wEmos.to_dict(orient='records')[0]
            wEmos_dict.pop('word')
            # print(wEmos_dict)
            return wEmos_dict
        else:
            if negDegNeg:
                wEmos = antiLex[antiLex['word'] == word]
                wEmos_dict = wEmos.to_dict(orient='records')[0]
                wEmos_dict.pop('word')
                # print(wEmos_dict)
                return wEmos_dict
            else:
                wEmos = antiAntiLex[antiAntiLex['word'] == word]
                wEmos_dict = wEmos.to_dict(orient='records')[0]
                wEmos_dict.pop('word')
                # print(wEmos_dict)
                return wEmos_dict 

# print(getWordEmos('高兴', negate = 0, negateFirst = False, degreeYes = True, degrees = 4))

def calcEmoGrpEmos(wList):
    negate = 0
    negateFirst = False
    degreeFirst = False
    negDegNeg = False
    degreeYes = False
    degrees = 1
    emoWords = []
    negDegWords = []

    grpEmos_dict = {'PA': 0, 'PA_Intensity': 0, 'PE': 0, 'PE_Intensity': 0, 'PD': 0, 'PD_Intensity': 0, 'PH': 0, 'PH_Intensity': 0, 'PG': 0, 'PG_Intensity': 0, 'PB': 0, 'PB_Intensity': 0, 
                    'PK': 0, 'PK_Intensity': 0, 'PF': 0, 'PF_Intensity': 0, 'PC': 0, 'PC_Intensity': 0, 'NAA': 0, 'NAA_Intensity': 0, 'NB': 0, 'NB_Intensity': 0, 
                    'NJ': 0, 'NJ_Intensity': 0, 'NH': 0, 'NH_Intensity': 0, 'NPF': 0, 'NPF_Intensity': 0, 'NI': 0, 'NI_Intensity': 0, 'NC': 0, 'NC_Intensity': 0, 
                    'NG': 0, 'NG_Intensity': 0, 'NE': 0, 'NE_Intensity': 0, 'ND': 0, 'ND_Intensity': 0, 'NN': 0, 'NN_Intensity': 0, 'NK': 0, 'NK_Intensity': 0, 'NL': 0, 'NL_Intensity': 0, 
                    'NPC': 0, 'NPC_Intensity': 0, 
                    'joy': 0, 'joy_Intensity': 0, 'sadness': 0, 'sadness_Intensity': 0, 'liking': 0, 'liking_Intensity': 0, 
                    'disgust': 0, 'disgust_Intensity': 0, 'anger': 0, 'anger_Intensity': 0, 'fear': 0, 'fear_Intensity': 0, 
                    'surprise': 0, 'surprise_Intensity': 0, 'anticipation': 0, 'anticipation_Intensity': 0, 'surprisePos': 0, 
                    'surprisePos_Intensity': 0, 'surpriseNeg': 0, 'surpriseNeg_Intensity': 0, 
                    'IntensityWithSign': 0, 'PolarityWithMagnitude': 0}

    for word in wList:
        if word in negateWords:
            negate += 1
            negDegWords.append('negation')
            if not degreeFirst:
                negateFirst = True
        elif word in degreeWords_dict:
            degreeYes = True
            negDegWords.append('degree')
            degrees *= degreeWords_dict[word]
            if not negateFirst:
                degreeFirst = True
        elif word in emoWordList:
            emoWords.append(word)
    
    if len(negDegWords) >= 3:
        if negDegWords[0] == 'negation' and negDegWords[1] == 'degree' and negDegWords[2] == 'negation':
            negDegNeg = True

    for word in emoWords:
        wEmos_dict = getWordEmos(word, negate = negate, negateFirst = negateFirst, negDegNeg = negDegNeg, degreeYes = degreeYes, degrees = degrees)
        grpEmos_dict = {key: grpEmos_dict[key] + wEmos_dict[key] for key in grpEmos_dict}

    return grpEmos_dict


def calcSongEmos(emoGrps):
    songEmos_dict = {'PA': 0, 'PA_Intensity': 0, 'PE': 0, 'PE_Intensity': 0, 'PD': 0, 'PD_Intensity': 0, 'PH': 0, 'PH_Intensity': 0, 'PG': 0, 'PG_Intensity': 0, 'PB': 0, 'PB_Intensity': 0, 
                    'PK': 0, 'PK_Intensity': 0, 'PF': 0, 'PF_Intensity': 0, 'PC': 0, 'PC_Intensity': 0, 'NAA': 0, 'NAA_Intensity': 0, 'NB': 0, 'NB_Intensity': 0, 
                    'NJ': 0, 'NJ_Intensity': 0, 'NH': 0, 'NH_Intensity': 0, 'NPF': 0, 'NPF_Intensity': 0, 'NI': 0, 'NI_Intensity': 0, 'NC': 0, 'NC_Intensity': 0, 
                    'NG': 0, 'NG_Intensity': 0, 'NE': 0, 'NE_Intensity': 0, 'ND': 0, 'ND_Intensity': 0, 'NN': 0, 'NN_Intensity': 0, 'NK': 0, 'NK_Intensity': 0, 'NL': 0, 'NL_Intensity': 0, 
                    'NPC': 0, 'NPC_Intensity': 0, 
                    'joy': 0, 'joy_Intensity': 0, 'sadness': 0, 'sadness_Intensity': 0, 'liking': 0, 'liking_Intensity': 0, 
                    'disgust': 0, 'disgust_Intensity': 0, 'anger': 0, 'anger_Intensity': 0, 'fear': 0, 'fear_Intensity': 0, 
                    'surprise': 0, 'surprise_Intensity': 0, 'anticipation': 0, 'anticipation_Intensity': 0, 'surprisePos': 0, 
                    'surprisePos_Intensity': 0, 'surpriseNeg': 0, 'surpriseNeg_Intensity': 0, 
                    'IntensityWithSign': 0, 'PolarityWithMagnitude': 0}

    for emoGrp in emoGrps:
        # print('emotion group: ' + str(emoGrp))
        grpEmos_dict = calcEmoGrpEmos(emoGrp)
        # print('group emotions: ' + str(grpEmos_dict))
        songEmos_dict = {key: songEmos_dict[key] + grpEmos_dict[key] for key in songEmos_dict}
    
    # print('song emotions: ' + str(songEmos_dict))

    return pd.Series(list(songEmos_dict.values()))


# Paralell processing

def process_chunk(chunk):
    return chunk.apply(calcSongEmos)

def parallel_apply(df, column_name, func, num_processes=None):
    print('processing')
    
    # Split DataFrame into chunks
    chunks = np.array_split(df[column_name], num_processes)

    start = time.time()

    # Create a multiprocessing pool and process chunks in parallel
    with Pool(processes=num_processes) as pool:
        results = pool.map(func, chunks)

    # total runtime
    runTime = time.time() - start
    print(str(runTime) + ' seconds')

    # Combine the results
    return pd.concat(results)

def main():

    for i in range(1, 30):

        df = pd.read_csv(f'Final Datasets/7.csv segments/df7_ch_synonym_expanded_after emoSplit {i}.csv', low_memory=False)
        # df = df.head(1000)
        df['threeEmotionsCH_split'] = df['threeEmotionsCH_split'].apply(lambda x: ast.literal_eval(x)) # need to do this for themeCH_split and other similar columns

        print('Current segment: ' + str(i))

        # Apply function in parallel
        df[column_names] = parallel_apply(df, 'threeEmotionsCH_split', process_chunk, num_processes=12)

        # Save the DataFrame to a CSV file
        df.to_csv(f'Final Datasets/7.csv segments/df7_3EmotionsCH_split_synonym_expanded_emo scores {i}.csv', index=False)
        print()

# This is the crucial part
if __name__ == '__main__':
    main()
